/**************************************************************
*   This software is confidential and contains code, algorithms 
* and know-how proprietary to Saber Interactive.
*
* Copyright (c), Saber Interactive, Inc. 2001-2011
***************************************************************
*
* M3D.H
*
* 2D & 3D math ('m3d', 'm2d', 'm3xz', ...)
*
* This is the main M3D header file that includes
* internal header files that should not be included
* independently
**************************************************************/

#ifndef _M3D_H_
#define _M3D_H_

#include <math.h>
//#include "ap\ap_comm.h"

//
// CPU types
// NOTE: these are mostly ignored by math functions now - use M3D_USE_SSE define instead
//
enum {
   M3D_SIMD_SSE,
   M3D_SIMD_3DNOW,
   M3D_SIMD_NONE,
};

#define M3D_SUPPRESS_OPTIMIZATION


#if (defined _AP_PC || defined _AP_XBOX) && !defined M3D_SUPPRESS_OPTIMIZATION
#define M3D_USE_SSE // use SSE math functions - undefine this to use CRT functions, which are slower but more accurate
#endif // M3D_SUPPRESS_OPTIMIZATION


//
// M3D main defines
//

//#define M3D_EPSILON        0.000001f
//#define M3D_INFINITY       2000000.f
//#define M3D_PI             3.14159265f
//#define M3D_FLOAT_UNDEF    888.888f
//#define M3D_SQRT_2         1.4142135623730950488f
//#define M3D_SQRT_2_INV     0.7071067811865475244f
//#define M3D_SQRT_3         1.7320508075688772935f
//#define M3D_SQRT_3_INV     0.5773502691896257645f
const float M3D_EPSILON        = 0.000001f;
const float M3D_EPSILON_2      = M3D_EPSILON * M3D_EPSILON;
const float M3D_INFINITY       = 2000000.f;
const float M3D_PI             = 3.14159265f;
const float M3D_FLOAT_UNDEF    = 888.888f;
const float M3D_SQRT_2         = 1.4142135623730950488f;
const float M3D_SQRT_2_INV     = 0.7071067811865475244f;
const float M3D_SQRT_3         = 1.7320508075688772935f;
const float M3D_SQRT_3_INV     = 0.5773502691896257645f;
const float M3D_FLT_MAX        = 3.402823466e+38F;
const float M3D_FLT_MIN        = 1.175494351e-38F;
const int   M3D_INT_MAX        = 2147483647;
const int   M3D_SHORT_MAX      = 32767;

//
// max number of vertices in polygons m3dPOLY / m2dPOLY
//
#define M3D_MAX_NVERT   20

//
// Common retcodes
//
// Retcodes for qualification routines
#define M3D_LAY_IN          -1
#define M3D_LAY_OUT          1
#define M3D_LAY_ON_BORDER    0

// Retcodes for qualification routines
#define M3D_INSIDE          -1  // Points/vectors... placement
#define M3D_OUTSIDE          1
#define M3D_ISECT            0

// Retcodes for routines dealing with complex bodies
// Ray/complex body intersections
#define M3D_ISECT_NO         0  // no intersection found
#define M3D_ISECT_YES        1  // intersection found
#define M3D_ISECT_BELONG     2  // object belongs to another object,
                                // intersection data is not computed

// Point/bvolume distance computations
#define M3D_DIST_NOTFOUND    0  // distance cannot be computed
#define M3D_DIST_FOUND       1  // distance successfully computed
#define M3D_DIST_BELONG      2  // point belongs to another object,
                                // distance data is not computed
//
// Options for vertex/matrix operations
//
#define M3D_REPLACE          0
#define M3D_PRE              1  // in transform in local coord space
#define M3D_POST             2  // in transform in parent coord space

//
// Six basic directions
//
enum {
   M3D_AXIS_Z_NEG,
   M3D_AXIS_X_POS,
   M3D_AXIS_Z_POS,
   M3D_AXIS_X_NEG,
   M3D_AXIS_Y_NEG,
   M3D_AXIS_Y_POS,
};

//#ifdef _AP_XENON
#if defined(_AP_XENON) || defined(_AP_PS3)
   #define  VID_USE_INVERTED_Z   // use for projection matrix
#endif

// use ifdef for your condition or _m3dCheckValid if it should be used in _RETAIL
#if defined(_RETAIL) || defined (_PROFILE) || defined(_PROFILE) || defined(_AP_PS3)
   #define m3dCheckValid  EMPTY_PROC
#else
   #define m3dCheckValid(x) (_m3dCheckValid(x))
#endif

BOOL  _m3dCheckValid (float number);
BOOL  _m3dCheckValid (const struct m4dV *v);
BOOL  _m3dCheckValid (const struct m3dV *v);
BOOL  _m3dCheckValid (const struct m2dV *v);
BOOL  _m3dCheckValid (const struct m3dVTX *v);

extern int             m3dSimdType;    // detected cpu SIMD instructions type (sse/3dnow/none) M3D_SIMD_...

//
// Internal includes
//
#include <m3d/m3d_vmx_helpers.h>
#include <m3d/m3d_math.h>
#include <m3d/m3d_vect.h>
#include <m3d/m3d_rect.h>
#include <m3d/m3d_line.h>
#include <m3d/m3d_poly.h>
#include <m3d/m3d_matr.h>
#include <m3d/m3d_quat.h>
#include <m3d/m3d_quatdual.h>
#include <m3d/m3d_vol.h>
#include <m3d/m3d_colr.h>
//#include <m3d/m3d_spl.h>
#include <m3d/m3d_noise.h>
#include <m3d/m3d_vox.h>
//#include <m3d/m3d_ctrl.h>
#include <m3d/m3d_rand.h>
//#include <m3d/m3d_tr.h>
//#include <m3d/m3d_trf.h>
//#include <m3d/m3d_trs.h>
#include <m3d/m3d_float2int.h>

//
// Global M3D functions
//
BOOL  m3dInit       (void);
void  m3dTerm       (void);

BOOL  m3dInitHW     (void);

void m3dEnableSimd  (BOOL enable = TRUE);
int  m3dGetSimdType (void);

/**************************************************************************
* m3dUpdateMax()                                                          *
*                                                                         *
**************************************************************************/
template <class T>
inline bool m3dUpdateMax(T & max_, T val) { if (max_ < val) { max_ = val; return true; } return false;}

/**************************************************************************
* m3dUpdateMin()                                                          *
*                                                                         *
**************************************************************************/
template <class T>
inline bool m3dUpdateMin(T & min_, T val) { if (min_ > val) { min_ = val; return true; } return false; }

template <class T>
inline void m3dUpdateMinMax(T & min_, T & max_, T val) { if (min_ > val) min_ = val; if (max_ < val) max_ = val; }

/**************************************************************************
* m3dMinMax()                                                             *
*                                                                         *
**************************************************************************/
template <class T>
inline T m3dMinMax(T value, T min, T max)
{
   if (value < min) {
      return min;
   }
   if (value > max) {
      return max;
   }
   return value;
}

/**************************************************************************
* m3dCheckFinite()                                                        *
*                                                                         *
**************************************************************************/
inline bool m3dCheckFinite(float val)
{
   if (!_m3dCheckValid(val)) {
      STRONG_ASSERT(!"Invalid float value");
      return false;
   }

   if (abs(val) > 2 * M3D_INFINITY) {
      ASSERT(!"Infinite float value"); // STRONG_ASSERT is too much here
      return false;
   }

   return true;
}

/**************************************************************************
* m3dCheckFinite()                                                        *
*                                                                         *
**************************************************************************/
inline bool _m3dCheckFinite(float val)
{
   if (!_m3dCheckValid(val)) {
      return false;
   }

   if (abs(val) > 2 * M3D_INFINITY) {
      return false;
   }

   return true;
}

/**************************************************************************
* m3dCheckFinite()                                                        *
*                                                                         *
**************************************************************************/
inline bool m3dCheckFinite(const m3dV & v)
{
   return m3dCheckFinite(v.x) && m3dCheckFinite(v.y) && m3dCheckFinite(v.z);
}

/**************************************************************************
* m3dCheckFinite()                                                        *
*                                                                         *
**************************************************************************/
inline bool _m3dCheckFinite(const m3dV & v)
{
   return _m3dCheckFinite(v.x) && _m3dCheckFinite(v.y) && _m3dCheckFinite(v.z);
}

/**************************************************************************
* m3dCheckMatrixValid()                                                        
*                                                                         
**************************************************************************/
inline bool m3dCheckMatrixValid (const m3dMATR &matr)
{
   for (int i=0; i<16; i++) {
      if (!_m3dCheckValid(matr.Element(i))) {
         return FALSE;
      }
   }
   return TRUE;
}

/**************************************************************************
* m3dCheckMatrixFinite()                                                        
*                                                                         
**************************************************************************/
inline bool m3dCheckMatrixFinite (const m3dMATR &matr)
{
   for (int i=0; i<16; i++) {
      if (!m3dCheckFinite(matr.Element(i))) {
         return FALSE;
      }
   }
   return TRUE;
}

#endif // _M3D_H_

//
// End-of-file M3D.H
//

